package com.ruoyi.business.controller;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.ruoyi.business.common.Result;
import com.ruoyi.business.entity.*;
import com.ruoyi.business.entity.alipay.AliPay;
import com.ruoyi.business.entity.dto.AddOrderDTO;
import com.ruoyi.business.entity.dto.CouponDTO;
import com.ruoyi.business.entity.dto.OrderDetail;
import com.ruoyi.business.entity.redis.UserObj;
import com.ruoyi.business.service.*;
import com.ruoyi.business.utils.DateTimeUtils;
import com.ruoyi.business.utils.MD5Util;
import com.ruoyi.business.utils.UserObjHolder;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.ibatis.annotations.Param;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
//import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.ruoyi.business.utils.RedisConstant.LOGIN_USER_KEY;
import static com.ruoyi.business.utils.RedisConstant.LOGIN_USER_TTL;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author Ao
 * @since 2024-01-08
 */
@RestController
@RequestMapping("business/user")
@Api(value = "用户信息接口", tags = "个人信息接口")
public class FrontUserController {

    @Autowired
    private FrontUserService userService;

    @Autowired
    private FrontOrdersService ordersService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private FrontHomestayInfoService homestayInfoService;

    @Autowired
    private FrontCouponUsedInfoService couponUsedInfoService;

    @Autowired
    private FrontCouponInfoService couponInfoService;


    @Autowired
    private FrontComplaintInfoService complaintInfoService;

    @Autowired
    private FrontSellerService sellerService;


    @PostMapping("/register")
    public Result<String> register(@RequestBody User user) {
        String password = user.getPassword();
        String hashedPassword = MD5Util.md5Password(password);
        user.setPassword(hashedPassword);
        userService.save(user);

        return Result.success("注册成功");
    }



    // 在类中定义一个BCryptPasswordEncoder实例
//    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    /**
     * 登录接口
     */
    @ApiOperation(value = "登录接口", notes = "登录接口")
    @PostMapping("/login")
    @Transactional
    public Result<Map<String, Object>> login(@Validated @RequestBody User user) {
        if (!StringUtils.hasLength(user.getUserid())
                || !StringUtils.hasLength(user.getPassword())) {
            return Result.error("用户名或密码为空!");
        }

        // 查看当前用户名[学号]是否存在
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUserid, user.getUserid());
        User dbUser = userService.getOne(wrapper);
        if (dbUser == null) {
            return Result.error("请输入正确的用户名!");
        }

        System.out.println(dbUser.getId());

        if (dbUser.getId() > 0) {

//            if (dbUser.getPassword().equals(user.getPassword())) {
            if (dbUser.getPassword().equals(MD5Util.md5Password(user.getPassword()))) {

                //账号密码正确
                //token等于随机字符串加学号，账号用于多次登录删除之前登录的key
                String token = UUID.randomUUID().toString(true).toString() + dbUser.getUserid() + "user";


                //返回给前端使用的
                HashMap<String, Object> result = new HashMap<>();
                result.put("token", token);
                result.put("userId", dbUser.getUserid());
                result.put("userName", dbUser.getUsername());

                //存入redis
                /**
                 * 存入redis
                 */

                //todo：转json存字符串
                UserObj userObj = BeanUtil.copyProperties(dbUser, UserObj.class);
                userObj.setType("user");
//
                String userJson = JSONUtil.toJsonStr(userObj);

                /**
                 * 加入redis之前，删除这个账号之前登录的key
                 */
                String pattern = "*" + dbUser.getUserid() + "user";
                Set<String> keys = stringRedisTemplate.keys(pattern);
                stringRedisTemplate.delete(keys);

                //存入redis--String类型
                stringRedisTemplate.opsForValue().set(LOGIN_USER_KEY + token, userJson);
                //设置有效期30分钟--String类型
                stringRedisTemplate.expire(LOGIN_USER_KEY + token, LOGIN_USER_TTL, TimeUnit.MINUTES);


                return Result.success(result);
            } else {
                return Result.error("账号密码错误!");
            }
        }

        return Result.error("账号异常");
    }

    @GetMapping("/logout")
    @ApiOperation("用户退退出登录接口")
    public Result<String> logout() {
        UserObj userObj = UserObjHolder.getUserObj();
        String userid = userObj.getUserid();

        //删除这个账号的redis数据
        String pattern = "*" + userid + "user";
        Set<String> keys = stringRedisTemplate.keys(pattern);
        stringRedisTemplate.delete(keys);

        return Result.success("退出登录成功");

    }


    @PostMapping("/orderList")
    @ApiOperation(value = "用户订单接口")
    public Result<List<Orders>> userOrderList(@RequestBody ReceiveData receiveData) {

        if (receiveData.getUserId() == null) {
            return Result.error("需要userId");
        }
        List<Orders> ordersList = ordersService.list(
                new LambdaQueryWrapper<Orders>()
                        .eq(receiveData.getUserId() != null, Orders::getUserid, receiveData.getUserId())

                        .eq(receiveData.getOrderStatus() != null, Orders::getOrderStatus, receiveData.getOrderStatus())
                        .eq(receiveData.getGoodsType() != null, Orders::getGoodsType, receiveData.getGoodsType())
        );

        return Result.success(ordersList);

    }


    @PostMapping("/searchOrderList")
    @ApiOperation(value = "查找用户订单接口")
    public Result<List<Orders>> searchOrderList(@RequestBody ReceiveData receiveData) {

        if (receiveData.getUserId() == null) {
            return Result.error("需要userId");
        }
        List<Orders> ordersList = ordersService.list(
                new LambdaQueryWrapper<Orders>()
                        .eq(receiveData.getUserId() != null, Orders::getUserid, receiveData.getUserId())

                        .eq(receiveData.getOrderStatus() != null, Orders::getOrderStatus, receiveData.getOrderStatus())
                        .eq(receiveData.getGoodsType() != null, Orders::getGoodsType, receiveData.getGoodsType())
                        .like(receiveData.getName() != null, Orders::getHomestayName, receiveData.getName())

        );

        return Result.success(ordersList);

    }


    @GetMapping("/myOrder")
    @ApiOperation(value = "我的订单页面接口")
    public Result<Map<String, Integer>> myOrder() {

        UserObj userObj = UserObjHolder.getUserObj();
        String userid = userObj.getUserid();

        List<Orders> ordersList = ordersService.list(
                new LambdaQueryWrapper<Orders>()
                        .eq(Orders::getUserid, userid)
        );

        //计算各种订单分类
        int num1 = ordersList.size();//总数
        int num2 = 0;
        int num3 = 0;
        int num4 = 0;

        for (Orders orders : ordersList) {
            switch (orders.getOrderStatus()) {
                case 1:
                    num2++;//预定订单
                    break;
                case 2:
                    num3++;//完成订单
                    break;
                case 3:
                    num4++;//退款订单
                    break;
                default:
                    return Result.error("订单类型出错");
            }
        }

        Map<String, Integer> result = new HashMap<>();
        result.put("num1", num1);
        result.put("num2", num2);
        result.put("num3", num3);
        result.put("num4", num4);

        return Result.success(result);

    }


    @GetMapping("/getinfo")
    @ApiOperation(value = "获取个人信息接口", tags = "获取个人信息接口")
    public Result<User> getUser() {
        String userid = UserObjHolder.getUserObj().getUserid();
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserid, userid);
        User one = userService.getOne(queryWrapper);
        return Result.success(one);

    }

    @PostMapping("/update")
    @ApiOperation(value = "个人信息修改接口", tags = "个人信息修改接口")
    public Result<User> update(@RequestBody User user) {
//        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        userLambdaQueryWrapper.eq(User::getUserid,user.getUserid());
//        boolean update = userService.update(userLambdaQueryWrapper);
        boolean b = userService.updateById(user);
        if (!b) {
            return Result.error("修改出错");
        }
        return Result.success(user);

    }

    //获取订单详情
    @ApiOperation(value = "订单详情", tags = "订单详情")
    @GetMapping("/getdetail")
    public Result<OrderDetail> getDetail(@Param("orderid") Long orderid) {
        if (orderid == null) {
            return Result.error("参数获取失败!");
        }
        //查询订单基本信息
        Orders order = ordersService.getById(orderid);
        if (order == null) {
            return Result.error("订单不存在");

        }
        //将现有的字段赋值
        OrderDetail orderDetail = BeanUtil.copyProperties(order, OrderDetail.class);

        //查询对应订单的民宿地址和商家信息
        HomestayInfo homestay = homestayInfoService.getById(orderDetail.getHomestayid());
        if (homestay == null) {
            return Result.error("商家信息不存在");
        }
        orderDetail.setHomestayaddress(homestay.getHomestayAddress());
        orderDetail.setHomertele(homestay.getHomerTele());

        return Result.success(orderDetail);


    }


    @ApiOperation(value = "修改订单信息", tags = "修改订单信息")
    @PostMapping("/updateorder")
    public Result<String> updateOrder(@RequestBody Orders orders) {
        if (orders == null) {
            return Result.error("参数获取失败!");
        }

        boolean b = ordersService.updateById(orders);

        if (!b) {
            return Result.error("修改失败！");
        }
        return Result.success("修改成功!");


    }


    @Autowired
    private FrontCommentsService commentsService;

    /**
     * 评价
     *
     * @param orders
     * @return
     */
    @Transactional
    @PostMapping("/evaluate")
    public Result<String> evaluate(@RequestBody Orders orders) { //

        String content = orders.getReason();
        orders.setReason("");
        ordersService.updateById(orders);

        //添加评价
        Long homestayid = orders.getHomestayid();
        Integer type = orders.getGoodsType();
        Long id = orders.getId();
        String userid = orders.getUserid();
        int user_type = 0;//用户
//        String str_Date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date().getTime());
        Comments comments = new Comments();
        comments.setHomestayId(homestayid);
        comments.setDiscussType(type);
        comments.setObjectId(id);
        comments.setUserid(userid);
        comments.setDiscussContent(content);
        comments.setParentDiscussId(0L);
        comments.setReplyNum(0L);
        comments.setUserType(user_type);

        // 获取当前时间
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        String strDate = timestamp.toString(); // 从timestamp.toString()获取的时间字符串
// 定义日期时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
// 将字符串解析为LocalDateTime
        LocalDateTime dateTime = LocalDateTime.parse(strDate, formatter);
// 将LocalDateTime设置到comments对象中
        comments.setDiscussTime(dateTime);

        commentsService.save(comments);


        return Result.success("修改成功!");


    }

    /**
     * 删除投诉
     *
     * @return
     */
    @GetMapping("/deleteComplaint")
    public Result<String> deleteComplaint(Long id) {

        complaintInfoService.removeById(id);

        return Result.success("删除投诉成功");
    }

    //查询我的优惠券列表
    @ApiOperation(value = "我的优惠券列表")
    @GetMapping("/mycouponlist")
    public Result<List<CouponDTO>> getMyList() {
        String userid = UserObjHolder.getUserObj().getUserid();
        if (userid == null) {
            return Result.error("参数获取失败！");
        }

        LambdaQueryWrapper<CouponUsedInfo> queryWrapper = new LambdaQueryWrapper<>();
        //查询用户未使用的优惠券
        queryWrapper.eq(CouponUsedInfo::getReceiverUserid, userid)
                .eq(CouponUsedInfo::getIsused, 0);
        List<CouponUsedInfo> list = couponUsedInfoService.list(queryWrapper);

        LocalDateTime curtime = DateTimeUtils.getCurrentLocalDateTime();
        //更新优惠券信息
        List<CouponInfo> list1 = couponInfoService.list();
        for (CouponInfo couponInfo : list1) {
            if (curtime.isAfter(couponInfo.getExpireTime())) {  //说明过期
                couponInfo.setIsExpired(1);
                couponInfoService.updateById(couponInfo);

            }
        }
        //判断优惠券是否过期,并补充优惠券信息
        List<CouponDTO> couponDTOList = new ArrayList<>();
        for (CouponUsedInfo coupon : list) {
            CouponInfo byId = couponInfoService.getById(coupon.getCouponId());
            CouponDTO couponDTO = BeanUtil.copyProperties(coupon, CouponDTO.class);
            couponDTO.setExpire(byId.getExpireTime());
            couponDTO.setSubsidy(byId.getSubsidy());
            couponDTO.setIsexpired(byId.getIsExpired());
            couponDTO.setTitle(byId.getTitle());
            couponDTOList.add(couponDTO);

        }


        return Result.success(couponDTOList);

    }


    //订单投诉
    @ApiOperation(value = "订单投诉")
    @PostMapping("/complaint/add")
    public Result<String> ComplaintAdd(@RequestBody ComplaintInfo complaintInfo) {

        if (complaintInfo == null) {
            return Result.error("参数获取失败!");
        }
        complaintInfo.setComplaintTime(DateTimeUtils.getCurrentLocalDateTime());
        //获取商家编号
        LambdaQueryWrapper<HomestayInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(HomestayInfo::getHomestayId, complaintInfo.getHomestayId());
        HomestayInfo one = homestayInfoService.getOne(queryWrapper);

        //通过商家编号获取商家信息
        LambdaQueryWrapper<Seller> l1 = new LambdaQueryWrapper<>();
        l1.eq(Seller::getUserid, one.getSellerId());

        Seller seller = sellerService.getOne(l1);


        complaintInfo.setSellerId(seller.getUserid());
        complaintInfo.setSellerName(seller.getUsername());
        complaintInfo.setSellerTele(seller.getTele());

        boolean save = complaintInfoService.save(complaintInfo);
        if (!save) {
            return Result.error("数据保存失败!");
        }
        return Result.success("投诉成功！");


    }

    //订单投诉判断
    @ApiOperation(value = "订单投诉判断")
    @GetMapping("/complaint/iscomplaint")
    public Result<Long> isComplaint(@Param("orderid") Long orderid) {
        String userid = UserObjHolder.getUserObj().getUserid();
        if (orderid == null || userid == null) {
            return Result.error("参数获取失败！");
        }
        LambdaQueryWrapper<ComplaintInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ComplaintInfo::getUserid, userid)
                .eq(ComplaintInfo::getOrderId, orderid);
        ComplaintInfo one = complaintInfoService.getOne(queryWrapper);
        if (one != null) {
            return Result.error("该订单已提交投诉！");
        }

        return Result.success(1L);


    }


    //投诉信息查询
    @ApiOperation(value = "用户投诉信息查询接口")
    @GetMapping("/mycomplaint")
    public Result<List<ComplaintInfo>> mycomplaint(@Param("status") Integer status) {
        String userid = UserObjHolder.getUserObj().getUserid();
        LambdaQueryWrapper<ComplaintInfo> queryWrapper = new LambdaQueryWrapper<>();
        if (status == null) {
            status = 0;
        }
        queryWrapper.eq(ComplaintInfo::getStatus, status);
        List<ComplaintInfo> list = complaintInfoService.list(queryWrapper);
        for (ComplaintInfo complaintInfo : list) {
            complaintInfo.setPictureList(Arrays.asList(complaintInfo.getPictures().split(",")));
        }
        return Result.success(list);

    }


    @PostMapping("/refund")
    @ApiOperation(value = "退款接口")
    public Result<String> refund(@RequestBody Orders orders) {

        ordersService.updateById(orders);

        return Result.success("申请退款中");
    }


    @PostMapping("/payment")
    public Result<String> payment(@RequestBody Orders orders) {
        ordersService.updateById(orders);

        return Result.success("支付成功");
    }


    @PostMapping("/confirmReceipt")
    public Result<String> confirmReceipt(@RequestBody Orders orders) {
        ordersService.updateById(orders);

        return Result.success("确认收货成功");
    }

//    @Autowired
//    private FrontCouponUsedInfoService couponUsedInfoService;
    @GetMapping("/myCoupon")
    public Result<List<CouponInfo>> myCoupon(){
        String userid = UserObjHolder.getUserObj().getUserid();
        LambdaQueryWrapper<CouponUsedInfo> l1=new LambdaQueryWrapper<>();
        l1.eq(CouponUsedInfo::getReceiverUserid,userid);
        List<CouponUsedInfo> list = couponUsedInfoService.list(l1);

        List<CouponInfo> couponInfoList=new ArrayList<>();

        for (CouponUsedInfo couponUsedInfo : list) {
            Long couponId = couponUsedInfo.getCouponId();
            LambdaQueryWrapper<CouponInfo> l2=new LambdaQueryWrapper<>();
            l2.eq(CouponInfo::getCouponId,couponId);

            CouponInfo couponInfo = couponInfoService.getOne(l2);

            couponInfoList.add(couponInfo);
        }
        return Result.success(couponInfoList);
    }

    @GetMapping("/seckill")
    public Result<Long> seckill(Long couponId) {
        String userid = UserObjHolder.getUserObj().getUserid();

        LambdaQueryWrapper<CouponInfo> l1 = new LambdaQueryWrapper<>();
        l1.eq(CouponInfo::getCouponId, couponId);

        CouponInfo one = couponInfoService.getOne(l1);
        if (one == null) {
            return Result.error("优惠卷不存在");
        }

        if (one.getStock() < 1) {
            return Result.error("库存不足");
        }


        /**
         * 重点:对满足两个条件的的代码抽象出来加锁
         * 保证 :锁释放后->spring事务提交完成数据库的更新->其他线程获取锁资源
         * 总结：2个条件一个处理
         *   条件：1，需要在方法内部加锁其中一部分代码   2，这部分代码涉及到数据库的事务提交(方法使用了@Transactional)
         *   处理，将代码抽取成方法上锁，对方法使用@Transactional事务控制
         */

        String final_str = userid.toString().intern();
        synchronized (final_str) { //加锁的对象应该是用户id，降低锁的粒度，只有同一个用户的id的线程才竞争同一个锁对象
            FrontUserController currentProxy = (FrontUserController) AopContext.currentProxy();//该实现类的代理对象是通过代理这个接口

            return currentProxy.synchronized_method1(couponId);

        }
    }

    @Transactional
    public Result synchronized_method1(Long couponId) {
        int one = couponUsedInfoService.count(
                new LambdaQueryWrapper<CouponUsedInfo>()
                        .eq(CouponUsedInfo::getCouponId, couponId)
                        .eq(CouponUsedInfo::getReceiverUserid, UserObjHolder.getUserObj().getUserid())
        );
        if (one > 0) {
            return Result.error("一人只能购买一单");
        }

        //扣减库存
        boolean flag = couponInfoService.update().
                setSql("stock=stock-1")
                .eq("coupon_id", couponId)


                .gt("stock", 0)  // 添加 where stock > 0 条件
                .update();


        //update set stock=stock-1 where voucher_id= 8 and stock>0  (stock=10)

        if (!flag) {
            return Result.error("库存不足");
        }


        //4,创建订单
        CouponUsedInfo voucherOrder = new CouponUsedInfo();

//        voucherOrder.setId(redisIdWorker.nextId("order"));//全局唯一id
        voucherOrder.setCouponId(couponId);
        voucherOrder.setReceiverUserid(UserObjHolder.getUserObj().getUserid());
        voucherOrder.setIsused(0);

        boolean save = couponUsedInfoService.save(voucherOrder);


        return Result.success(voucherOrder.getReceiveId());

    }

    @Autowired
    private FrontTotalOrderService totalOrderService;
    /**
     * 添加订单
//     * @param addOrderDTO
     * @return
     */
    @PostMapping("/addOrder")
    @Transactional
    public Result<AliPay> addOrder(@RequestBody List<Orders> ordersList ) {

        LocalDateTime currentTime = LocalDateTime.now();


        //获得房间订单
//        List<Orders> allList = addOrderDTO.getOrdersList();
        List<Orders> allList = ordersList;
        Orders roomOrder = allList.get(0);
        Float totalPrice = roomOrder.getTotalPrice();
        Long id1 = roomOrder.getId();
        roomOrder.setCreateTime(currentTime);

//        Orders roomOrder = addOrderDTO.getRoomOrder();
        ordersService.save(roomOrder);
        Long id = roomOrder.getId();

        //修改优惠卷使用信息
        Long couponid = roomOrder.getCouponid();
        if(couponid!=null){
            String userid = roomOrder.getUserid();
            LambdaQueryWrapper<CouponUsedInfo> l1 = new LambdaQueryWrapper<>();
            l1.eq(CouponUsedInfo::getReceiverUserid, userid)
                    .eq(CouponUsedInfo::getCouponId, couponid);
            CouponUsedInfo one = couponUsedInfoService.getOne(l1);
            one.setIsused(1);//设置成已使用
            couponUsedInfoService.updateById(one);
        }


        //保存特色订单相关信息
        List<Long> list=new ArrayList<>();
        list.add(roomOrder.getId());
        allList.remove(roomOrder);
        Long id2 = roomOrder.getId();
        List<Orders> featureList = allList;
//        List<Orders> featureList = addOrderDTO.getFeatureList();
        for (Orders orders : featureList) {
            orders.setCreateTime(currentTime);
            orders.setRoomOrderid(id);
        }
        ordersService.saveBatch(featureList);


        for (Orders orders : ordersList) {
            list.add(orders.getId());
        }


        String uuid = UUID.randomUUID().toString(true).toString();
        //添加到总订单表
        for (Long orderId : list) {
            TotalOrder totalOrder = new TotalOrder();
            totalOrder.setTotalPrice(totalPrice);
            totalOrder.setUuidOrderId(uuid);
            totalOrder.setOrderId(orderId);

            totalOrderService.save(totalOrder);
        }

        AliPay aliPay = new AliPay();
        aliPay.setTraceNo(uuid);
        aliPay.setTotalAmount(totalPrice);
        aliPay.setSubject("订单");

        return Result.success(aliPay);
    }
}

